//
// Created by wangjunjun on 2024/3/11.
//

#include "alarmImage.hpp"
#include "../log/log.h"
#include "../config/configmanager.h"
#include "json.h"
#include "value.h"

#include <iostream>
#include <thread>
#include <chrono>
#include <ctime>
#include <sys/stat.h>
#include <vector>
#include <utility> // for std::pair
#include "../mission/ftpupload.h"

#include "ros/ros.h"
#include "std_msgs/Float32.h"

std::shared_ptr<CAlarmImage> CAlarmImage::m_Instance = nullptr;
std::once_flag CAlarmImage::m_flag;

// 构造函数，初始化成员变量
CAlarmImage::CAlarmImage() : m_cameraIp("192.168.11.64"), m_Distance(0.0) {
    init();
}

// 析构函数
CAlarmImage::~CAlarmImage() {}

// 初始化函数
void CAlarmImage::init() {
    // 不需要在此处调用 ros::init()，应在 main 函数中完成初始化
    distSubscriber = nh.subscribe("/odom", 10, &CAlarmImage::distanceCallback, this);  // 订阅 /dist 话题

    // 读取配置文件
    std::shared_ptr<CConfigManager> pIntance = CConfigManager::GetInstance();
    if (nullptr != pIntance) {
        std::string strPath = "./CFG/config";
        Json::Value tempValue = Json::Value::null;
        if (!pIntance->loadConfig(strPath, tempValue)) {
            LOG_ERROR("Loading Config error!");
            return;
        } else {
            if (tempValue.isMember("streamUrl") && tempValue["streamUrl"].isString()) {
                m_VideoStream = tempValue["streamUrl"].asString();
            }
            if (tempValue.isMember("tempertureThreshold") && tempValue["tempertureThreshold"].isInt()) {
                m_TemperatureThreshold = tempValue["tempertureThreshold"].asInt();
            }
            if (tempValue.isMember("DogSN") && tempValue["DogSN"].isString()) {
                m_Sn = tempValue["DogSN"].asString();
            }
            if (tempValue.isMember("cameraIp") && tempValue["cameraIp"].isString()) {
                m_cameraIp = tempValue["cameraIp"].asString();
            }
            if (tempValue.isMember("port") && tempValue["port"].isInt()) {
                m_port = tempValue["port"].asInt();
            }
            LOG_INFO("m_VideoStream:{} , m_TemperatureThreshold:{}", m_VideoStream, m_TemperatureThreshold);
            LOG_INFO("m_Sn:{} ,m_port:{} ", m_Sn, m_port);
            LOG_INFO("m_cameraIp:{} ", m_cameraIp);
            std::shared_ptr<CFtpUpload> ptrFtp = CFtpUpload::GetInStance();
            if (ptrFtp != nullptr) {
                ptrFtp->Start();
            }
        }
    }
}

// 单例模式获取实例
std::shared_ptr<CAlarmImage> CAlarmImage::GetInStance() {
    std::call_once(m_flag, []() {
        m_Instance = std::shared_ptr<CAlarmImage>(new CAlarmImage(), [](CAlarmImage* ptr) { delete ptr; });
    });
    return m_Instance;
}

// 启动函数，初始化相机和视频流处理
bool CAlarmImage::start() {
    try {
        // 初始化相机连接
        initCamera(m_cameraIp, m_port);

        // 连接视频流
        VideoCapture cap = reconnectVideoStream(m_VideoStream);

        // 开始处理视频帧
        processFrames(cap);
    } catch (const std::exception& e) {
        LOG_ERROR("Error: {}", e.what());
        return false;
    }
    return true;
}

// 初始化相机
void CAlarmImage::initCamera(const std::string& cameraIp, int port) {
    camera.connect_camera(cameraIp, port);
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));  // 等待相机连接
    int iConnectCnt = 0;
    while (!camera.init() && iConnectCnt < MAX_RETRY_CONNECT_CNT) {
        iConnectCnt++;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        LOG_INFO("Connecting to camera... ip:{} cnt:{}", cameraIp, iConnectCnt);
    }
    if (!camera.init()) {
        LOG_ERROR("Failed to initialize camera.");
    }
}

// 处理视频帧
void CAlarmImage::processFrames(VideoCapture& cap) {
    try {
        while (ros::ok()) {  // 使用 ros::ok() 检查 ROS 节点状态
            if (!cap.isOpened()) {
                LOG_ERROR("视频流已断开，尝试重连...");
                cap = reconnectVideoStream(m_VideoStream);
                continue;
            }

            Mat frame;
            cap >> frame;

            if (frame.empty()) {
                LOG_ERROR("读取图像失败，尝试重连视频流...");
                cap.release();
                cap = reconnectVideoStream(m_VideoStream);
                continue;
            }

            time_t currentTime = time(nullptr);
            std::vector<std::pair<Mat, time_t>> frameHistory;
            frameHistory.push_back({frame.clone(), currentTime});

            if (camera.init()) {
                auto temperatureData = camera.get_current_temperature();
                if (!temperatureData.empty()) {
                    int maxTemperature = temperatureData[0] / 100;
                    int maxX = temperatureData[1];
                    int maxY = temperatureData[2];

                    std::cout << "Max Temperature: " << std::dec << maxTemperature << " °C at ("
                              << std::dec << maxX << ", " << std::dec << maxY << ")" << std::endl;

                    if (maxTemperature > m_TemperatureThreshold) {
                        processFrame(frame, maxTemperature, maxX, maxY);
                        std::this_thread::sleep_for(std::chrono::seconds(3));
                    }
                }
            } else {
                LOG_ERROR("相机未初始化，无法获取温度数据");
            }
        }
    } catch (const std::exception& e) {
        LOG_ERROR("Error in processFrames: {}", e.what());
    }
}

// 获取当前时间的字符串格式
std::string CAlarmImage::getCurrentTimeString() {
    time_t rawTime;
    struct tm* timeInfo;
    char buffer[80];
    time(&rawTime);
    timeInfo = localtime(&rawTime);
    strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", timeInfo);
    return std::string(buffer);
}

// 创建保存图像的目录，使用接收到的距离数据
std::string CAlarmImage::createSaveDirectory() {
    std::string basePath = m_Sn;
    std::string timeString = getCurrentTimeString();
    std::string subfolder = std::to_string(static_cast<int>(m_Distance)) + "/";  // 使用 m_Distance 替换 0000
    std::string fullPath = basePath + "/" + timeString + "/" + subfolder;
    mkdir(basePath.c_str(), 0755);
    mkdir((basePath + "/" + timeString).c_str(), 0755);
    mkdir(fullPath.c_str(), 0755);
    return fullPath;
}

// 重新连接视频流
VideoCapture CAlarmImage::reconnectVideoStream(const std::string& stream) {
    VideoCapture cap;
    int retryCount = 0;
    while (retryCount <= MAX_RETRY_CONNECT_CNT) {
        cap.open(stream);
        if (cap.isOpened()) {
            LOG_INFO("视频流已重新连接: {}", stream);
            break;
        }
        LOG_INFO("无法连接视频流，正在重试...");
        std::this_thread::sleep_for(std::chrono::seconds(2));
        retryCount++;
    }

    if (!cap.isOpened()) {
        LOG_ERROR("视频流重连失败，超过最大重试次数.");
        throw std::runtime_error("Failed to reconnect video stream.");
    }
    return cap;
}

// 处理单个视频帧，保存图像
void CAlarmImage::processFrame(Mat& frame, int maxTemperature, int maxX, int maxY) {
    std::string saveDirectory = createSaveDirectory();
    std::string timeString = getCurrentTimeString();
    std::string savePath = saveDirectory + timeString + "__splice.jpg";
    Mat closestFrame = frame.clone(); // 使用当前帧作为最接近的帧
    int boxSize = 100;
    Point topLeft(maxX - boxSize / 2, maxY - boxSize / 2);
    Point bottomRight(maxX + boxSize / 2, maxY + boxSize / 2);
    rectangle(closestFrame, topLeft, bottomRight, Scalar(0, 0, 255), 2);

    std::ostringstream tempStream;
    tempStream << std::fixed << std::setprecision(2) << maxTemperature << " °C";
    putText(closestFrame, tempStream.str(), Point(topLeft.x, topLeft.y - 10), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);

    saveFrame(closestFrame, savePath);
    LOG_INFO("保存图像: {}", savePath);
}

// 保存帧图像
void CAlarmImage::saveFrame(const Mat& frame, const std::string& savePath) {
    imwrite(savePath, frame);
}

// ROS 话题回调函数，接收 /dist 话题的距离数据
void CAlarmImage::distanceCallback(const std_msgs::Float32::ConstPtr& msg) {
    m_Distance = msg->data;
    LOG_INFO("Received distance data: {}", m_Distance);
}
